home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr26 / netprog.zip / NETPROG.TAR / rmt / rmtd.c < prev   
C/C++ Source or Header  |  1989-12-17  |  9KB  |  346 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. char copyright[] =
  20. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  21.  All rights reserved.\n";
  22. #endif /* not lint */
  23.  
  24. #ifndef lint
  25. static char sccsid[] = "@(#)rmt.c    5.4 (Berkeley) 6/29/88";
  26. #endif /* not lint */
  27.  
  28. /*
  29.  * rmt daemon.
  30.  */
  31.  
  32. #include    <stdio.h>
  33. #include    <sgtty.h>
  34. #include    <sys/types.h>
  35. #include    <sys/socket.h>
  36. #include    <sys/mtio.h>
  37. #include    <errno.h>
  38. extern int    errno;
  39.  
  40. int    tapefd = -1;        /* file descriptor for tape device */
  41.  
  42. char    *record = NULL;        /* pointer to our malloc'ed buffer */
  43.  
  44. #define    MAXSTRING    64
  45. char    device[MAXSTRING];    /* device/filename to open */
  46. char    count[MAXSTRING];    /* count for read(2) and write(2) and others */
  47. char    offset[MAXSTRING];    /* offset for lseek(2) */
  48. char    whence[MAXSTRING];    /* whence for lseek(2) */
  49. char    mode[MAXSTRING];    /* mode for open(2) */
  50. char    op[MAXSTRING];        /* operation for mt ioctl */
  51.  
  52. char    respstr[BUFSIZ];    /* response string we send back to client */
  53.  
  54. long    lseek();
  55. long    atol();
  56. char    *malloc();
  57. char    *checkbuf();        /* our function, at end of file */
  58.  
  59. FILE    *debug;
  60. #define    DEBUG(f)    if (debug) fprintf(debug, f)
  61. #define    DEBUG1(f,a)    if (debug) fprintf(debug, f, a)
  62. #define    DEBUG2(f,a1,a2)    if (debug) fprintf(debug, f, a1, a2)
  63.  
  64. main(argc, argv)
  65. int    argc;
  66. char    **argv;
  67. {
  68.     int        n, i, cc, respval;
  69.     long        lrespval;
  70.     char        c;
  71.     struct mtop    mtop;
  72.     struct mtget    mtget;
  73.  
  74.     argc--, argv++;
  75.     if (argc > 0) {
  76.         /*
  77.          * If a command line argument is specified, take that as the
  78.          * name of a file to write debugging information into.
  79.          */
  80.  
  81.         if ( (debug = fopen(*argv, "w")) == NULL)
  82.             exit(1);
  83.         setbuf(debug, NULL);    /* completely unbuffered */
  84.     }
  85.  
  86.     /*
  87.      * We communicate with the client on descriptors 0 and 1.
  88.      * Since we're invoked by rshd, both are set to the stream socket
  89.      * that inetd accepts from the client.
  90.      * We read from fd 0 and write to fd 1, so that for testing we can
  91.      * just invoke this program interactively and it'll work with
  92.      * stdin and stdout.
  93.      */
  94. top:
  95.     errno   = 0;        /* Unix errno, clear before every operation */
  96.  
  97.     if (read(0, &c, 1) != 1)
  98.         exit(0);    /* EOF (normal way to end) or error */
  99.  
  100.     switch (c) {
  101.  
  102.     case 'O':                        /* open */
  103.         if (tapefd >= 0)
  104.             close(tapefd);    /* implies a close of currently-open
  105.                        device */
  106.         get_string(device);
  107.         get_string(mode);
  108.         DEBUG2("rmtd: O %s %s\n", device, mode);
  109.  
  110.         if ( (tapefd = open(device, atoi(mode))) < 0)
  111.             resp_ioerr(errno);
  112.         else
  113.             resp_val((long) 0);
  114.         break;
  115.  
  116.     case 'C':                        /* close */
  117.         DEBUG("rmtd: C\n");
  118.         get_string(device);        /* required, but ignored */
  119.  
  120.         if (close(tapefd) < 0)
  121.             resp_ioerr(errno);
  122.         else
  123.             resp_val((long) 0);
  124.  
  125.         tapefd = -1;    /* will force any i/o operations to generate
  126.                    an error, until another device is opened */
  127.         break;
  128.  
  129.     case 'L':                        /* lseek */
  130.         get_string(offset);
  131.         get_string(whence);
  132.         DEBUG2("rmtd: L %s %s\n", offset, whence);
  133.  
  134.         if ( (lrespval = lseek(tapefd, atol(offset), atoi(whence))) < 0)
  135.             resp_ioerr(errno);
  136.         else
  137.             resp_val(lrespval);    /* lseek return value */
  138.         break;
  139.  
  140.     case 'W':                        /* write */
  141.         get_string(count);
  142.         DEBUG1("rmtd: W %s\n", count);
  143.  
  144.         n = atoi(count);
  145.         record = checkbuf(record, n, SO_RCVBUF);
  146.  
  147.         /*
  148.          * We have to loop, to read a record of the specified size
  149.          * from the socket.
  150.          */
  151.  
  152.         for (i = 0; i < n; i += cc) {
  153.             if ( (cc = read(0, &record[i], n - i)) <= 0) {
  154.                 DEBUG("rmtd: premature eof\n");
  155.                 exit(2);
  156.             }
  157.         }
  158.  
  159.         /*
  160.          * Write a single tape record.  Note that we don't respond to
  161.          * the client until the write(2) system call returns.
  162.          */
  163.  
  164.         if ( (respval = write(tapefd, record, n)) < 0)
  165.             resp_ioerr(errno);
  166.         else
  167.             resp_val((long) respval);    /* #bytes written */
  168.         break;
  169.  
  170.     case 'R':                        /* read */
  171.         get_string(count);
  172.         DEBUG1("rmtd: R %s\n", count);
  173.  
  174.         n = atoi(count);
  175.         record = checkbuf(record, n, SO_SNDBUF);
  176.  
  177.         if ( (respval = read(tapefd, record, n)) < 0)
  178.             resp_ioerr(errno);
  179.         else {
  180.             resp_val((long) respval);    /* #bytes */
  181.             resp_buff(record, respval);    /* the actual data */
  182.         }
  183.         break;
  184.  
  185.     case 'I':                        /* MT ioctl */
  186.         get_string(op);
  187.         get_string(count);
  188.         DEBUG2("rmtd: I %s %s\n", op, count);
  189.  
  190.         mtop.mt_op    = atoi(op);
  191.         mtop.mt_count = atoi(count);
  192.         if (ioctl(tapefd, MTIOCTOP, (char *) &mtop) < 0)
  193.             resp_ioerr(errno);
  194.         else
  195.             resp_val((long) mtop.mt_count);
  196.         break;
  197.  
  198.     case 'S':                        /* MT status */
  199.         DEBUG("rmtd: S\n");
  200.  
  201.         if (ioctl(tapefd, MTIOCGET, (char *) &mtget) < 0)
  202.             resp_ioerr(errno);
  203.         else {
  204.             resp_val((long) sizeof(mtget));
  205.             resp_buff((char *) &mtget, sizeof(mtget));
  206.         }
  207.         break;
  208.  
  209.     default:
  210.         DEBUG1("rmtd: garbage command %c\n", c);
  211.         exit(3);
  212.     }
  213.     goto top;
  214. }
  215.  
  216. /*
  217.  * Send a normal response to the client.
  218.  */
  219.  
  220. resp_val(lval)
  221. long    lval;        /* has to be a long, for lseek() return value */
  222. {
  223.     register int    n;
  224.  
  225.     DEBUG1("rmtd: A %ld\n", lval);
  226.  
  227.     sprintf(respstr, "A%ld\n", lval);
  228.     n = strlen(respstr);
  229.     if (write(1, respstr, n) != n) {
  230.         DEBUG("rmtd: resp_val: write error\n");
  231.         exit(5);
  232.     }
  233. }
  234.  
  235. /*
  236.  * Send a response buffer to the client.
  237.  */
  238.  
  239. resp_buff(buff, nbytes)
  240. char    *buff;
  241. int    nbytes;
  242. {
  243.     if (write(1, buff, nbytes) != nbytes) {
  244.         DEBUG("rmtd: resp_buff: write error\n");
  245.         exit(6);
  246.     }
  247. }
  248.  
  249. /*
  250.  * Send an error response to the client.
  251.  * Notice that we send the error string associated with "errno" to the
  252.  * client, not just the errno value, since if it is a different flavor
  253.  * of Unix (or not even Unix at all) the errno values may not be
  254.  * meaningful.
  255.  */
  256.  
  257. resp_ioerr(errnum)
  258. int    errnum;        /* the Unix errno */
  259. {
  260.     char        msgstr[100];
  261.     extern int    sys_nerr;
  262.     extern char    *sys_errlist[];
  263.  
  264.     if (errnum > 0 && errnum < sys_nerr)
  265.         sprintf(msgstr, "%s", sys_errlist[errnum]);
  266.     else
  267.         sprintf(msgstr, "errno = %d", errnum);
  268.  
  269.     DEBUG2("rmtd: E %d (%s)\n", errnum, msgstr);
  270.     sprintf(respstr, "E%d\n%s\n", errnum, msgstr);
  271.     resp_buff(respstr, strlen(respstr));
  272. }
  273.  
  274. /*
  275.  * Get a string from the command line (the socket).
  276.  */
  277.  
  278. get_string(bp)
  279. char    *bp;        /* string gets stored here by us */
  280. {
  281.     register int    i;
  282.     register char    *cp;
  283.  
  284.     cp = bp;
  285.     for (i = 0; i < (MAXSTRING - 1); i++) {
  286.         /*
  287.          * Read one byte at a time, looking for the newline.
  288.          * Note that this differs from the rmt(8C) man page.
  289.          * Commands with multiple arguments (such as 'O') require
  290.          * a newline between the arguments.  Also, we do not skip
  291.          * over any leading white space, so the command character
  292.          * must be immediately followed by the first argument.
  293.          */
  294.  
  295.         if (read(0, cp+i, 1) != 1)
  296.             exit(0);
  297.  
  298.         if (cp[i] == '\n')
  299.             break;
  300.     }
  301.     cp[i] = '\0';
  302. }
  303.  
  304. /*
  305.  * The following function is called before every record is written or read
  306.  * to or from the tape.  Since we have to read or write every tape record
  307.  * with a single read(2) or write(2) system call, we have to assure
  308.  * we have a buffer that is big enough.
  309.  * What we do is keep track of the largest record we've seen so far, and
  310.  * whenever a larger record is required, we free(3) the old buffer and
  311.  * malloc(3) a new one.
  312.  *
  313.  * Additionally, when we malloc a buffer, we set the socket's buffer size
  314.  * to the new size (or as close to it as possible).
  315.  */
  316.  
  317. static int    maxrecsize = -1;    /* largest record we've seen so far */
  318.  
  319. char *            /* return pointer to buffer to use */
  320. checkbuf(ptr, size, option)
  321. char    *ptr;        /* pointer to current buffer */
  322. int    size;        /* size of current buffer */
  323. int    option;        /* for setsockopt: SO_SNDBUF or SO_RCVBUF */
  324. {
  325.  
  326.     if (size <= maxrecsize)
  327.         return(ptr);        /* current buffer is big enough */
  328.  
  329.     if (ptr != NULL)
  330.         free(ptr);        /* first free the existing buffer */
  331.                     /* then malloc a new buffer */
  332.     if ( (ptr = malloc(size)) == NULL) {
  333.         DEBUG("rmtd: cannot allocate buffer space\n");
  334.         exit(4);
  335.     }
  336.  
  337.     maxrecsize = size;        /* remember new buffer size */
  338.  
  339.     while ((size > 1024) &&
  340.            (setsockopt(0, SOL_SOCKET, option, (char *) &size,
  341.                 sizeof(size)) < 0))
  342.         size -= 1024;
  343.  
  344.     return(ptr);        /* return pointer to the new buffer */
  345. }
  346.